`CFX_FolderFontInfo` 类是 PDFium 项目中用于管理和查找系统字体的核心类之一。它实现了 `SystemFontInfoIface` 接口，提供了扫描文件夹、枚举字体列表、映射字体等功能，确保在渲染 PDF 文档时能够正确找到并使用系统中的可用字体。以下是 `CFX_FolderFontInfo` 类的详细解析：

### 类定义

```cpp
class CFX_FolderFontInfo : public SystemFontInfoIface {
public:
  CFX_FolderFontInfo();
  ~CFX_FolderFontInfo() override;

  void AddPath(const ByteString& path);

  // SystemFontInfoIface:
  bool EnumFontList(CFX_FontMapper* pMapper) override;
  void* MapFont(int weight,
    bool bItalic,
    FX_Charset charset,
    int pitch_family,
    const ByteString& face) override;
  void* GetFont(const ByteString& face) override;
  size_t GetFontData(void* hFont,
    uint32_t table,
    pdfium::span<uint8_t> buffer) override;
  void DeleteFont(void* hFont) override;
  bool GetFaceName(void* hFont, ByteString* name) override;
  bool GetFontCharset(void* hFont, FX_Charset* charset) override;

protected:
  friend class CFXFolderFontInfoTest;

  class FontFaceInfo {
  public:
    static constexpr int32_t kSimilarityScoreMax = 68;

    FontFaceInfo(ByteString filePath,
      ByteString faceName,
      ByteString fontTables,
      uint32_t fontOffset,
      uint32_t fileSize);

    bool IsEligibleForFindFont(uint32_t flag, FX_Charset charset) const;
    int32_t SimilarityScore(int weight,
      bool italic,
      int pitch_family,
      bool exact_match_bonus) const;

    const ByteString m_FilePath;
    const ByteString m_FaceName;
    const ByteString m_FontTables;
    const uint32_t m_FontOffset;
    const uint32_t m_FileSize;
    uint32_t m_Styles = 0;
    uint32_t m_Charsets = 0;
  };

  void ScanPath(const ByteString& path);
  void ScanFile(const ByteString& path);
  void ReportFace(const ByteString& path,
    FILE* pFile,
    FX_FILESIZE filesize,
    uint32_t offset);
  void* GetSubstFont(const ByteString& face);
  void* FindFont(int weight,
    bool bItalic,
    FX_Charset charset,
    int pitch_family,
    const ByteString& family,
    bool bMatchName);

  std::map<ByteString, std::unique_ptr<FontFaceInfo>> m_FontList;
  std::vector<ByteString> m_PathList;
  UnownedPtr<CFX_FontMapper> m_pMapper;
};
```

### 主要功能

#### 1. * *构造和析构 * *

-**构造函数 * *：
- `CFX_FolderFontInfo()`：初始化 `CFX_FolderFontInfo` 对象，设置默认状态。

- **析构函数 * *：
- `~CFX_FolderFontInfo()`：释放资源，确保所有分配的内存都被正确释放。

#### 2. * *路径管理 * *

-**添加路径 * *：
- `AddPath(const ByteString & path)`：将指定的文件夹路径添加到扫描列表中。通过调用 `ScanPath` 方法，PDFium 会扫描该路径下的所有字体文件，并将其信息存储在 `m_FontList` 中。

#### 3. * *字体枚举 * *

-**枚举字体列表 * *：
- `EnumFontList(CFX_FontMapper * pMapper)`：枚举系统中的所有字体，并将它们注册到 `CFX_FontMapper` 中。`CFX_FontMapper` 是一个用于字体替换和匹配的工具，确保在找不到确切字体时可以找到最接近的替代字体。

#### 4. * *字体映射 * *

-**映射字体 * *：
- `MapFont(int weight, bool bItalic, FX_Charset charset, int pitch_family, const ByteString& face)`：根据给定的字体属性（如粗细、斜体、字符集、间距族和字体名称），查找并返回一个匹配的字体句柄。如果找不到完全匹配的字体，PDFium 会尝试找到最相似的字体。

- **获取字体 * *：
- `GetFont(const ByteString & face)`：根据字体名称直接获取字体句柄。如果字体名称匹配，则返回相应的字体句柄；否则返回 `nullptr`。

- **获取字体数据 * *：
- `GetFontData(void* hFont, uint32_t table, pdfium::span<uint8_t> buffer)`：获取指定字体表的数据，并将其写入提供的缓冲区中。这通常用于访问字体的内部结构，如 `cmap`、`glyf` 等表。

- **删除字体 * *：
- `DeleteFont(void* hFont)`：释放指定的字体句柄，确保资源被正确回收。

- **获取字体名称 * *：
- `GetFaceName(void* hFont, ByteString* name)`：根据字体句柄获取字体的家族名称，并将其存储在 `name` 参数中。

- **获取字体字符集 * *：
- `GetFontCharset(void* hFont, FX_Charset* charset)`：根据字体句柄获取字体的字符集，并将其存储在 `charset` 参数中。

#### 5. * *字体信息管理 * *

-**内部字体信息类 * *：
- `FontFaceInfo`：这是一个嵌套类，用于存储每个字体面的详细信息。它包括字体文件路径、字体名称、字体表数据、偏移量、文件大小等。此外，它还提供了两个重要的方法：
- `IsEligibleForFindFont(uint32_t flag, FX_Charset charset)`：检查字体是否符合给定的标志和字符集要求。
- `SimilarityScore(int weight, bool italic, int pitch_family, bool exact_match_bonus)`：计算字体与给定属性之间的相似度得分，用于在找不到完全匹配的字体时选择最接近的替代字体。

#### 6. * *字体扫描和报告 * *

-**扫描路径 * *：
- `ScanPath(const ByteString & path)`：递归扫描指定路径下的所有文件夹和文件，查找字体文件并将它们的信息存储在 `m_FontList` 中。

- **扫描文件 * *：
- `ScanFile(const ByteString & path)`：扫描单个文件，检查它是否为有效的字体文件。如果是，则调用 `ReportFace` 方法报告该字体。

- **报告字体 * *：
- `ReportFace(const ByteString & path, FILE* pFile, FX_FILESIZE filesize, uint32_t offset)`：读取字体文件的内容，提取字体面信息，并将其存储在 `m_FontList` 中。

#### 7. * *字体查找 * *

-**获取替代字体 * *：
- `GetSubstFont(const ByteString & face)`：根据字体名称查找并返回一个替代字体句柄。如果找不到匹配的字体，则返回 `nullptr`。

- **查找字体 * *：
- `FindFont(int weight, bool bItalic, FX_Charset charset, int pitch_family, const ByteString& family, bool bMatchName)`：根据给定的字体属性查找最匹配的字体。如果 `bMatchName` 为 `true`，则优先匹配字体名称；否则仅根据其他属性进行匹配。

### 成员变量

- **`m_FontList`* * ：
- 类型：`std::map<ByteString, std::unique_ptr<FontFaceInfo>>`
- 描述：存储所有已扫描的字体面信息，键为字体名称，值为 `FontFaceInfo` 对象的智能指针。

- **`m_PathList`* * ：
- 类型：`std::vector<ByteString>`
- 描述：存储用户通过 `AddPath` 方法添加的所有文件夹路径。

- **`m_pMapper`* * ：
- 类型：`UnownedPtr<CFX_FontMapper > `
- 描述：指向 `CFX_FontMapper` 的未拥有指针，用于字体替换和匹配。

### 实际应用

`CFX_FolderFontInfo` 类在 PDFium 中主要用于以下场景：

1. * *字体加载和扫描 * *：
- 在启动时或需要更新字体列表时，`CFX_FolderFontInfo` 会扫描指定的文件夹路径，查找并加载所有可用的字体文件。这些字体信息会被存储在 `m_FontList` 中，供后续使用。

2. * *字体匹配和替换 * *：
- 当 PDF 文档中引用的字体在系统中不可用时，`CFX_FolderFontInfo` 会根据文档中指定的字体属性（如粗细、斜体、字符集等）查找最匹配的替代字体。`CFX_FontMapper` 会帮助完成这一过程，确保文本渲染的准确性。

3. * *跨平台支持 * *：
- `CFX_FolderFontInfo` 可以在不同平台上工作，因为它依赖于 FreeType 字体库来处理字体文件。无论是在 Windows、Linux 还是 macOS 上，`CFX_FolderFontInfo` 都能可靠地管理和查找系统字体。

4. * *字体数据访问 * *：
- `CFX_FolderFontInfo` 提供了访问字体表数据的功能，这对于实现高级字体特性（如 OpenType 特性）非常重要。通过 `GetFontData` 方法，可以获取字体的内部结构信息，从而实现更复杂的文本布局和渲染。

### 总结

`CFX_FolderFontInfo` 类是 PDFium 中用于管理和查找系统字体的关键组件。它不仅实现了 `SystemFontInfoIface` 接口，提供了丰富的字体管理和查找功能，还通过 `FontFaceInfo` 类封装了每个字体面的详细信息。通过 `CFX_FolderFontInfo`，PDFium 能够在不同平台上高效地加载、枚举和匹配字体，确保 PDF 文档中的文本能够正确显示。// Copyright 2016 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#ifndef CORE_FXGE_CFX_FOLDERFONTINFO_H_
#define CORE_FXGE_CFX_FOLDERFONTINFO_H_

#include <map>
#include <memory>
#include <vector>

#include "core/fxcrt/fx_codepage_forward.h"
#include "core/fxcrt/unowned_ptr.h"
#include "core/fxge/cfx_fontmapper.h"
#include "core/fxge/systemfontinfo_iface.h"

#define CHARSET_FLAG_ANSI (1 << 0)
#define CHARSET_FLAG_SYMBOL (1 << 1)
#define CHARSET_FLAG_SHIFTJIS (1 << 2)
#define CHARSET_FLAG_BIG5 (1 << 3)
#define CHARSET_FLAG_GB (1 << 4)
#define CHARSET_FLAG_KOREAN (1 << 5)

class CFX_FolderFontInfo : public SystemFontInfoIface {
 public:
  CFX_FolderFontInfo();
  ~CFX_FolderFontInfo() override;

  void AddPath(const ByteString& path);

  // SystemFontInfoIface:
  bool EnumFontList(CFX_FontMapper* pMapper) override;
  void* MapFont(int weight,
                bool bItalic,
                FX_Charset charset,
                int pitch_family,
                const ByteString& face) override;
  void* GetFont(const ByteString& face) override;
  size_t GetFontData(void* hFont,
                     uint32_t table,
                     pdfium::span<uint8_t> buffer) override;
  void DeleteFont(void* hFont) override;
  bool GetFaceName(void* hFont, ByteString* name) override;
  bool GetFontCharset(void* hFont, FX_Charset* charset) override;

 protected:
  friend class CFXFolderFontInfoTest;

  class FontFaceInfo {
   public:
    static constexpr int32_t kSimilarityScoreMax = 68;

    FontFaceInfo(ByteString filePath,
                 ByteString faceName,
                 ByteString fontTables,
                 uint32_t fontOffset,
                 uint32_t fileSize);

    bool IsEligibleForFindFont(uint32_t flag, FX_Charset charset) const;
    int32_t SimilarityScore(int weight,
                            bool italic,
                            int pitch_family,
                            bool exact_match_bonus) const;

    const ByteString m_FilePath;
    const ByteString m_FaceName;
    const ByteString m_FontTables;
    const uint32_t m_FontOffset;
    const uint32_t m_FileSize;
    uint32_t m_Styles = 0;
    uint32_t m_Charsets = 0;
  };

  void ScanPath(const ByteString& path);
  void ScanFile(const ByteString& path);
  void ReportFace(const ByteString& path,
                  FILE* pFile,
                  FX_FILESIZE filesize,
                  uint32_t offset);
  void* GetSubstFont(const ByteString& face);
  void* FindFont(int weight,
                 bool bItalic,
                 FX_Charset charset,
                 int pitch_family,
                 const ByteString& family,
                 bool bMatchName);

  std::map<ByteString, std::unique_ptr<FontFaceInfo>> m_FontList;
  std::vector<ByteString> m_PathList;
  UnownedPtr<CFX_FontMapper> m_pMapper;
};

#endif  // CORE_FXGE_CFX_FOLDERFONTINFO_H_
